﻿using AutoMapper;
using MediatR;
using ProduceBasicData.Api.Application.Command.ReceiveMaterials;
using ProduceBasicData.Api.DTO;
using ProduceBasicData.Api.Services;
using ProduceBasicData.Domain.FactoryModeling;
using ProduceBasicData.Domain.Material;
using ProduceBasicData.Domain.ProductionManage;
using ProduceBasicData.Domain.WarehouseManage;
using ProduceBasicData.Domain.WarehouseManage.WarehouseEnum;
using ProduceBasicData.ErrorCode;
using ProduceBasicData.Infrastructure.Interface;

namespace ProduceBasicData.Api.Application.Handler.ReceiveMaterials
{
    /// <summary>
    /// 领料处理
    /// </summary>
    public class ReceiveMaterialsHandler : IRequestHandler<ReceiveMaterialsCommand, ApiResult<int>>
    {
        private readonly IBaseRespository<Workshopmodel> workRepo;
        private readonly IBaseRespository<StockOutOrder> outRepo;
        private readonly IBaseRespository<Work_order> workorderRepo;
        private readonly IBaseRespository<BOMInfoModel> bomRepo;
        private readonly IBaseRespository<WorkShopOrder> workShopOrderRepo;
        private readonly IBaseRespository<StockOutOrderItem> stockOutOrderItemRepo;
        private readonly ICodeRuleService codeRuleService;
        private readonly IMapper mapper;

        public ReceiveMaterialsHandler(IBaseRespository<Workshopmodel> workRepo,
            IBaseRespository<StockOutOrder> outRepo,
            IBaseRespository<Work_order> workorderRepo,
            IBaseRespository<BOMInfoModel> bomRepo,
            IBaseRespository<WorkShopOrder> workShopOrderRepo,
            IBaseRespository<StockOutOrderItem> stockOutOrderItemRepo,
            ICodeRuleService codeRuleService,
            IMapper mapper)
        {
            this.workRepo = workRepo;
            this.outRepo = outRepo;
            this.workorderRepo = workorderRepo;
            this.bomRepo = bomRepo;
            this.workShopOrderRepo = workShopOrderRepo;
            this.stockOutOrderItemRepo = stockOutOrderItemRepo;
            this.codeRuleService = codeRuleService;
            this.mapper = mapper;
        }

        public async Task<ApiResult<int>> Handle(ReceiveMaterialsCommand request, CancellationToken cancellationToken)
        {
            ApiResult<int> res = new ApiResult<int>();

            try
            {
                // 验证车间信息是否存在
                var workshop = await workRepo.GetModelAsync(request.WorkshopmodelId);
                if (workshop == null)
                {
                    res.Code = ApiEnum.Failed;
                    res.Msg = "当前车间信息不存在";
                    return res;
                }

                // 通过车间-工单中间表获取所有关联的工单信息
                var workShopOrders = workShopOrderRepo.GetAll()
                    .Where(x => x.WorkshopId == request.WorkshopmodelId)
                    .ToList();
                
                if (!workShopOrders.Any())
                {
                    res.Code = ApiEnum.Failed;
                    res.Msg = "车间未关联任何工单信息";
                    return res;
                }

                // 获取所有工单信息并计算总BOM用量
                var totalBomDosage = 0;
                var workOrders = new List<Work_order>();
                
                foreach (var workShopOrder in workShopOrders)
                {
                    var workOrder = await workorderRepo.GetModelAsync(workShopOrder.WorkorderId);
                    if (workOrder != null)
                    {
                        workOrders.Add(workOrder);
                        // 计算每个工单的BOM用量
                        var bomDosage = await CalculateTotalBomDosage(workOrder.Product_id);
                        totalBomDosage +=bomDosage*workOrder.Order_number;
                    }
                }

                if (totalBomDosage == 0)
                {
                    res.Code = ApiEnum.Failed;
                    res.Msg = "所有工单的BOM信息不存在或用量为0";
                    return res;
                }

                // 将BOM总用量存储到车间数量字段
                workshop.ShopNum = totalBomDosage;
                await workRepo.Update(workshop);

                // 生成出库单编码
                string orderNumber;
                if (!string.IsNullOrEmpty(request.OrderNumber))
                {
                    orderNumber = request.OrderNumber;
                }
                else
                {
                    // 使用自动编码生成规则
                    var autoGeneratedCode = await codeRuleService.AutoGenerateCodeAsync("ProduceBasicData.Domain.WarehouseManage.StockOutOrder");
                    if (!string.IsNullOrEmpty(autoGeneratedCode))
                    {
                        orderNumber = autoGeneratedCode;
                    }
                    else
                    {
                        // 如果没有配置规则，使用默认生成方式
                        orderNumber = $"O{DateTime.Now:yyyyMMddHHmmss}";
                    }
                }

                // 创建出库单
                var stockOutOrder = new StockOutOrder
                {
                    OrderNumber = orderNumber,
                    Remark = request.Remark,
                    ExpectedOutDate=DateTime.Now,
                    CreateName = request.CreateName,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                    OutType= StockOutType.Production,//生产领料
                    Status= StockOutStatus.InProgress, //出库中
                    Num= totalBomDosage, //领料数量
                    
                };

                // 保存出库单
                await outRepo.AddAsync(stockOutOrder);

                // 为每个工单创建出库单明细记录
                foreach (var workOrder in workOrders)
                {
                    //var bomDosage = await CalculateTotalBomDosage(workOrder.Product_id);
                    
                    var stockOutOrderItem = new StockOutOrderItem
                    {
                        StockOutOrderId = stockOutOrder.Id,
                        WorkshopmodelId = request.WorkshopmodelId,
                        MaterialId = workOrder.Product_id, // 使用工单的产品ID作为物料ID
                        PlannedQuantity = totalBomDosage,
                        ActualQuantity = 0, // 初始实际数量为0
                        CreateName = request.CreateName,
                        CreateTime = DateTime.Now,
                        UpdateTime = DateTime.Now
                    };

                    // 保存出库单明细 (AddAsync方法内部已包含SaveChangesAsync)
                    await stockOutOrderItemRepo.AddAsync(stockOutOrderItem);
                }

                // 领料完成操作后，将工单状态改为5(领料中)
                foreach (var workOrder in workOrders)
                {
                    workOrder.Status = 6; // 领料中状态
                    workOrder.UpdateTime = DateTime.Now;
                    workOrder.UpdateName = request.CreateName;
                    await workorderRepo.Update(workOrder);
                }

                res.Code = ApiEnum.Success;
                res.Msg = "领料申请提交成功";
                res.Data = stockOutOrder.Id;
            }
            catch (Exception ex)
            {
                res.Code = ApiEnum.Failed;
                res.Msg = $"领料申请失败：{ex.Message}";
            }

            return res;
        }

        /// <summary>
        /// 递归计算BOM总用量
        /// </summary>
        /// <param name="bomId">BOM ID</param>
        /// <returns>总用量</returns>
        private async Task<int> CalculateTotalBomDosage(int bomId)
        {
            var bom = await bomRepo.GetModelAsync(bomId);
            if (bom == null)
            {
                return 0;
            }

            // 获取当前BOM的用量
            var currentDosage = bom.BOMDosage ?? 0;

            // 获取所有子级BOM
            var childBoms = bomRepo.GetAll()
                .Where(x => x.ParentBOMId == bomId && !x.Isdel)
                .ToList();

            // 递归计算子级BOM用量
            var childDosage = 0;
            foreach (var childBom in childBoms)
            {
                childDosage += await CalculateTotalBomDosage(childBom.Id);
            }

            // 返回当前用量 + 子级用量
            return currentDosage + childDosage;
        }
    }
}
